
#pragma once

namespace atr {

/**
 * @brief Namespace only for internal use of atr library
 * @details Please don't use this namespace outside the atr library. IF you REALLY need to - do it with special care.
 */
namespace __ {

template <typename Base, typename Iterator, typename ... Types> struct __insert;

    ////////////////////
    // Values

template <template <class ...> class Base, typename ... Types,
          template <class, class> class Iterator, typename ... Prevs,
                                                  typename ... Nexts,
          typename ... NewTypes>
struct __insert<Base<Types...>,
                Iterator<Base<Prevs...>, Base<Nexts...>>, NewTypes...>
{
    static_assert(std::is_same<Base<Types...>, Base<Prevs..., Nexts...>>::value,
                  "<Position> iterator have to belong to proper container");
    using type = Base<Prevs..., NewTypes..., Nexts...>;
};

    ////////////////////
    // First Last

template <template <class ...> class Base, typename ... Types,
          template <class, class> class Iterator, typename ... Prevs,
                                                  typename ... Nexts,
          template <class ...> class NewBase,
                typename ... FirstNexts,
                typename ... LastPrevs, typename ... LastNexts>
struct __insert<Base<Types...>,
                Iterator<Base<Prevs...>, Base<Nexts...>>,
                Iterator<NewBase<>, NewBase<FirstNexts...>>,
                Iterator<NewBase<LastPrevs...>, NewBase<LastNexts...>>>
{
    static_assert(std::is_same<Base<Types...>, Base<Prevs..., Nexts...>>::value,
                  "<Position> iterator have to belong to proper container");
    static_assert(std::is_same<NewBase<FirstNexts...>,
                               NewBase<LastPrevs..., LastNexts...>>::value,
                  "<First> have to be from same container than <Last>");

    using type = Base<Prevs..., LastPrevs..., Nexts...>;
};

template <template <class ...> class Base, typename ... Types,
          template <class, class> class Iterator, typename ... Prevs,
                                                  typename ... Nexts,
          template <class ...> class NewBase,
                typename First, typename ... FirstPrevs, typename ... FirstNexts,
                typename Last, typename ... LastPrevs, typename ... LastNexts>
struct __insert<Base<Types...>,
                Iterator<Base<Prevs...>, Base<Nexts...>>,
                Iterator<NewBase<First, FirstPrevs...>, NewBase<FirstNexts...>>,
                Iterator<NewBase<Last, LastPrevs...>, NewBase<LastNexts...>>>
    : public __insert<Base<Types...>,
                      Iterator<Base<Prevs...>, Base<Nexts...>>,
                      Iterator<NewBase<FirstPrevs...>, NewBase<FirstNexts...>>,
                      Iterator<NewBase<LastPrevs...>, NewBase<LastNexts...>>>
{
    static_assert(std::is_same<Base<Types...>, Base<Prevs..., Nexts...>>::value,
                  "<Position> iterator have to belong to proper container");
    static_assert(std::is_same<NewBase<First, FirstPrevs..., FirstNexts...>,
                               NewBase<Last, LastPrevs..., LastNexts...>>::value,
                  "<First> have to be from same container than <Last>");
};

// TODO insert - n val

} // namespace __
} // namespace atr